﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.Collections.Generic;
using System.Linq;

using Refix.Core.Options;
using Refix.Core.Properties;
using Refix.Core.Repository;

namespace Refix.Core.Commands
{
    public abstract class Command
    {
        static public readonly IDictionary<string, Type> KnownCommands =
            new Dictionary<string, Type>
                {
                    {"help", typeof(Help)},
                    {"alternative", typeof(Alternative)},
                    {"alt", typeof(Alternative)},
                    {"register", typeof(Register)},
                    {"reg", typeof(Register)},
                    {"unregister", typeof(Unregister)},
                    {"unreg", typeof(Unregister)},
                    {"clean", typeof(Clean)},
                    {"inject", typeof(Inject)},
                    {"inj", typeof(Inject)},
                    {"resolve", typeof(Resolve)},
                    {"res", typeof(Resolve)},
                    {"prebuild", typeof(Prebuild)},
                    {"pre", typeof(Prebuild)},
                    {"fix", typeof(Fix)},
                    {"get", typeof(Get)},
                    {"visualize", typeof(Visualize)},
                    {"vis", typeof(Visualize)},
                    {"view", typeof(View)},
                    {"find", typeof(Find)},
                    {"version", typeof(Version)},
                    {"ver", typeof(Version)},
                    {"postbuild", typeof(Postbuild)},
                    {"post", typeof(Postbuild)},
                    {"solution", typeof(Solution)},
                    {"sln", typeof(Solution)},
                    {"upload", typeof(Upload)},
                    {"up", typeof(Upload)},
                    {"obsolete", typeof(Obsolete)},
                    {"obs", typeof(Obsolete)},
                    {"sourcecontrol", typeof(SourceControl)},
                    {"scc", typeof(SourceControl)},
                    {"synchronize", typeof(Synchronize)},
                    {"sync", typeof(Synchronize)},
                };

        public CommandWithOptions Options { get; set; }
        protected abstract string HelpText { get; }

        protected LocalRepository GetLocalRepository()
        {
            var repository = Options.Options.FirstOrDefault(o => o is Options.Repository) as Options.Repository;
            return repository == null ? new LocalRepository() : new LocalRepository(repository.Path);
        }

        static public bool TryParse(Queue<string> queue, out Command command)
        {
            command = null;
            if (queue.Count == 0)
            {
                OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("PROGRAM_MISSING_COMMAND"));
                return false;
            }
            string commandName = queue.Dequeue();
            return TryParse(commandName, out command);
        }

        static protected bool TryParse(string commandName, out Command command)
        {
            command = null;
            if (!KnownCommands.ContainsKey(commandName))
            {
                OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("PROGRAM_UNKNOWN_COMMAND"),
                                   commandName);
                return false;
            }
            command = (Command)Activator.CreateInstance(KnownCommands[commandName]);
            return true;
        }

        public virtual bool Validate()
        {
            ShowSplash();
            if (Options.Options.Any(o => o is Verbose)
                && Options.Options.Any(o => o is Quiet))
            {
                OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("OPTION_INVALID_COMBINATION"));
                ShowHelp();
                return false;
            }
            return true;
        }

        public abstract bool Execute();

        public void ShowSplash()
        {
            if (Options.Options.Any(o => o is NoSplash))
            {
                return;
            }
            OutputWriter.WriteLine(ResourceDispenser.GetString("VERSION"),
                               typeof(Command).Assembly.GetName().Version);
            OutputWriter.WriteLine(ResourceDispenser.GetString("COPYRIGHT"));
            OutputWriter.WriteLine();
        }

        public void ShowHelp()
        {
            OutputWriter.WriteLine(OutputVerbosity.Quiet, HelpText);
        }
    }
}